/****************************************************************************
 *
 * Copyright (C) 2003-2008 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
package nfse.gui.server;

import nfse.*;
import nfse.stats.StatsServer;
import nfse.gui.client.ReportService;
import nfse.gui.client.reports.*;
import nfse.gui.client.data.*;

import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.*;
import java.sql.*;
import java.io.*;

public class ReportServiceImpl extends NetFSEServiceServlet implements ReportService {

    public ReportServiceImpl() {
        super();

    }

    public TopValues getTopValues(String queryID, int type, int field, int n, String where) {
        Statement s = null;
        TopValues temp = new TopValues();
        try {
            s = createResultStatement();
            String fieldName = NetFSE.getFieldName(field);

            String where2 = "";
            if (where.length() > 0)
                where2 = " where " + where;

            String sql = "";
            ResultSet rs = null;
            try {
                sql = "select " + fieldName + ", count(*) as a from " + queryID + "_" + type + " " + where2
                        + " group by " + fieldName + " order by a desc limit " + n;
                // System.out.println("1." + sql);
                s = resultConnection.createStatement();
                rs = s.executeQuery(sql);
            } catch (Exception e) {
                // e.printStackTrace();
                // rs.close();
                s.close();
                return temp;
            }

            int total = 0;

            Vector<String> values = new Vector<String>();
            Vector<Integer> counts = new Vector<Integer>();
            while (rs.next()) {
                values.addElement(rs.getString(fieldName));
                int count = new Integer(rs.getInt("a"));
                total += count;
                counts.addElement(count);
            }
            rs.close();

            temp.total = NetFSEUtil.formattedInteger(total);

            if (values.size() == 0) {
                s.close();
                return temp;
            }

            // Determine time interval

            sql = " select min(startts) as a, max(startts) as b from " + queryID + "_" + type + " " + where2 + " ";
            // System.out.println("2. " + sql);
            rs = s.executeQuery(sql);
            rs.next();
            Timestamp minTS = rs.getTimestamp("a");
            Timestamp maxTS = rs.getTimestamp("b");
            temp.startTS = minTS.toString();
            temp.endTS = maxTS.toString();
            rs.close();

            long intervalCount = 50;
            long diff = maxTS.getTime() - minTS.getTime();
            diff = diff / 1000; // convert from millis to seconds

            long val = Math.round(diff / intervalCount);
            if (val == 0)
                val++;

            temp.stats = new int[values.size()][50];
            temp.highs = new String[values.size()];
            temp.lows = new String[values.size()];
            temp.totals = new String[values.size()];
            temp.values = new String[values.size()];
            temp.percents = new String[values.size()];

            temp.columnAlignment = new String[8];
            temp.columnAlignment[0] = "LEFT";
            temp.columnAlignment[1] = "RIGHT";
            temp.columnAlignment[2] = "LEFT";
            temp.columnAlignment[3] = "RIGHT";
            temp.columnAlignment[4] = "RIGHT";
            temp.columnAlignment[5] = "RIGHT";
            temp.columnAlignment[6] = "RIGHT";
            temp.columnAlignment[7] = "RIGHT";
            temp.columnName = new String[8];
            temp.columnName[0] = "Value";
            temp.columnName[1] = "Start";
            temp.columnName[2] = "";
            temp.columnName[3] = "End";
            temp.columnName[4] = "Low";
            temp.columnName[5] = "High";
            temp.columnName[6] = "Total";
            temp.columnName[7] = "% Activity";

            for (int i = 0; i < values.size(); i++) {
                int min = -1;
                int max = -1;
                temp.values[i] = (String) values.elementAt(i);
                if (field == NetFSE.FIELD_PROTOCOL) {
                    temp.values[i] = NetFSEUtil.getProtocolName(Integer.parseInt(temp.values[i]));
                }
                temp.totals[i] = NetFSEUtil.formattedInteger((Integer) counts.elementAt(i));
                temp.percents[i] = NetFSEUtil.formattedDouble(((float) (Integer) counts.elementAt(i)) / (float) total
                        * 100.0);
                String where3 = "";
                if (where.length() > 0)
                    where3 = "(" + where + ") and ";

                sql = "select " + fieldName + ", count(*) as b, trunc(extract(epoch from startts)/" + val
                        + ") as a from " + queryID + "_" + type + " where " + where3 + fieldName + "='"
                        + values.elementAt(i) + "' group by " + fieldName + ", a limit " + intervalCount;
                // System.out.println("3. " + sql);
                int oopsVal = -1;
                rs = s.executeQuery(sql);
                while (rs.next()) {
                    int count = rs.getInt("b");
                    if (count > max) {
                        max = count;
                    }
                    if (min == -1 || count < min) {
                        min = count;
                    }

                    long time = (rs.getLong("a") * val);
                    long idx2 = time - (minTS.getTime() / 1000);
                    int idx = (int) (idx2 / val);
                    if (idx >= intervalCount) {
                        oopsVal = count;
                    } else if (idx < 0) {
                        // no op
                    } else {
                        temp.stats[i][idx] = count;
                    }
                }
                rs.close();
                temp.lows[i] = NetFSEUtil.formattedInteger(min);
                temp.highs[i] = NetFSEUtil.formattedInteger(max);

                if (oopsVal != -1) {
                    for (int j = 1; j < temp.stats[i].length; j++) {
                        temp.stats[i][j - 1] = temp.stats[i][j];
                    }
                    temp.stats[i][(int) intervalCount - 1] = oopsVal;
                }

            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                s.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return temp;
    }

    public Statement createStatsStatement() {
        try {

            Class.forName("org.postgresql.Driver");
            String url = "jdbc:postgresql://" + NetFSE.STATS_DB_HOST + "/" + NetFSE.STATS_DB_DATABASE;
            Properties props = new Properties();
            props.setProperty("user", NetFSE.STATS_DB_USER);
            props.setProperty("password", NetFSE.STATS_DB_PASSWORD);
            props.setProperty("client_encoding", "UTF8");

            if (statsConnection == null) {
                try {
                    statsConnection = DriverManager.getConnection(url, props);
                } catch (Exception e) {

                }
            }
            Statement s = null;
            try {
                s = statsConnection.createStatement();
            } catch (Exception e2) {
                try {
                    statsConnection = DriverManager.getConnection(url, props);
                    s = statsConnection.createStatement();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return s;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public StatsResult getDstIPStats(int[] sensors, int count, int units, boolean includeToday, int direction) {
        return getStats("Destination IP", "dst_ip_stats", "IP", sensors, count, units, includeToday, direction);
    }

    private StatsResult getStats(String name, String tableName, String colName, int[] sensors, int count, int units,
            boolean includeToday, int direction) {
        try {
            Vector<StatEntry> temp = new Vector<StatEntry>();
            GregorianCalendar today = new GregorianCalendar();
            today.set(Calendar.HOUR_OF_DAY, 0);
            today.set(Calendar.MINUTE, 0);
            today.set(Calendar.SECOND, 0);
            today.set(Calendar.MILLISECOND, 0);
            today.add(Calendar.SECOND, -1);
            if (includeToday)
                today.add(Calendar.DAY_OF_MONTH, 1);

            GregorianCalendar then = new GregorianCalendar();
            if (units != -1) {
                then.setTimeInMillis(today.getTimeInMillis());
                then.add(Calendar.SECOND, 1);
                then.add(units, -1 * count);
            } else {
                then.setTimeInMillis(0);
            }

            String sensorSQL = "";
            if (sensors[0] != -1) {
                sensorSQL = " and (";
                for (int i = 0; i < sensors.length; i++) {
                    if (i > 0)
                        sensorSQL += "or";
                    sensorSQL += " Sensor_ID=" + sensors[i] + " ";
                }
                sensorSQL += ")";
            }

            long minVal = -1;
            long maxVal = -1;

            int otherDirection = StatsServer.DIRECTION_OUTGOING;
            if (direction == StatsServer.DIRECTION_OUTGOING)
                otherDirection = StatsServer.DIRECTION_INCOMING;

            Statement s = createStatsStatement();

            String sql = "select min(Time_Interval) as a , max(Time_Interval) as b from " + tableName
                    + " where Time_Interval < " + today.getTimeInMillis() / 1000 + " and Time_Interval >= "
                    + then.getTimeInMillis() / 1000 + " " + sensorSQL;

            ResultSet rs = s.executeQuery(sql);
            rs.next();

            long minTS = rs.getLong("a");
            long maxTS = rs.getLong("b");
            rs.close();

            StatsResult result = new StatsResult();
            result.direction = direction;
            result.minTS = new Timestamp(minTS * 1000).toString();
            Timestamp maxTimestamp = new Timestamp((maxTS + StatsServer.INTERVAL) * 1000);
            if (maxTimestamp.getTime() > System.currentTimeMillis())
                maxTimestamp = new Timestamp(System.currentTimeMillis());
            result.maxTS = maxTimestamp.toString();
            result.title = name + " Activity";

            String directionSQL = "";
            if (direction != 0)
                directionSQL = "Direction = " + direction + " and ";

            sql = "select " + colName + ", sum(Num_Hits) as a from " + tableName + " where " + directionSQL
                    + "Time_Interval < " + today.getTimeInMillis() / 1000 + " and Time_Interval >= "
                    + then.getTimeInMillis() / 1000 + " " + sensorSQL + " group by " + colName
                    + " order by a desc limit 5";
            rs = s.executeQuery(sql);
            while (rs.next()) {
                String value = rs.getString(colName);
                Long numHits = rs.getLong("a");
                // String dt = rs.getString("dt");
                if (minVal == -1 || minVal > numHits)
                    minVal = numHits;
                if (maxVal == -1 || maxVal < numHits)
                    maxVal = numHits;

                StatEntry se = new StatEntry();
                se.key = value;
                if (direction == StatsServer.DIRECTION_OUTGOING) {
                    se.outgoingValueDisplay = NetFSEUtil.formattedInteger(numHits);
                    se.outgoingValue = "" + numHits;
                } else {
                    se.incomingValue = "" + numHits;
                    se.incomingValueDisplay = NetFSEUtil.formattedInteger(numHits);
                }
                // se.date = dt;
                temp.addElement(se);
            }
            rs.close();
            // s.close();
            StatEntry[] stats = new StatEntry[temp.size()];
            for (int i = 0; i < stats.length; i++) {
                stats[i] = (StatEntry) temp.elementAt(i);
            }
            result.stats = stats;

            if (direction != 0) {
                for (int i = 0; i < stats.length; i++) {
                    String where = "";
                    if (colName.equals("IP"))
                        where = colName + "='" + stats[i].key + "'";
                    else
                        where = colName + "=" + stats[i].key + "";
                    sql = "select sum(Num_Hits) as a from " + tableName + " where " + where + " and Direction = "
                            + otherDirection + " and Time_Interval < " + today.getTimeInMillis() / 1000
                            + " and Time_Interval >= " + then.getTimeInMillis() / 1000 + " " + sensorSQL + " ";
                    rs = s.executeQuery(sql);
                    if (rs.next()) {
                        Long numHits = rs.getLong("a");
                        // String dt = rs.getString("dt");
                        if (minVal == -1 || minVal > numHits)
                            minVal = numHits;
                        if (maxVal == -1 || maxVal < numHits)
                            maxVal = numHits;

                        if (otherDirection == StatsServer.DIRECTION_OUTGOING) {
                            stats[i].outgoingValueDisplay = NetFSEUtil.formattedInteger(numHits);
                            stats[i].outgoingValue = "" + numHits;
                        } else {
                            stats[i].incomingValueDisplay = NetFSEUtil.formattedInteger(numHits);
                            stats[i].incomingValue = "" + numHits;
                        }
                    }
                    rs.close();
                }
            }
            s.close();

            result.maxValue = maxVal;
            result.minValue = minVal;
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new StatsResult();
    }

    public StatsResult getSrcIPStats(int[] sensors, int count, int units, boolean includeToday, int direction) {
        return getStats("Source IP", "src_ip_stats", "IP", sensors, count, units, includeToday, direction);
    }

    public StatsResult getDstPortStats(int[] sensors, int count, int units, boolean includeToday, int direction) {
        return getStats("Destination Port", "dst_port_stats", "Port", sensors, count, units, includeToday, direction);
    }

    public StatsResult getProtocolStats(int[] sensors, int count, int units, boolean includeToday, int direction) {
        return getStats("Protocol", "protocol_stats", "Protocol", sensors, count, units, includeToday, direction);
    }

    /**
     * This handles getting the stats fro event stats from the metadata and
     * stats databases
     * 
     * @param timePeriod
     * @return
     */
    public HashMap<String, EventStats> getEventStats(String timePeriod) {
        nfse.gui.client.data.EventStats eventStats;

        HashMap<String, EventStats> localMap = new HashMap<String, EventStats>();
        try {

            // Get the stats from the filled tables which means that no more
            // records can go in. Only when the table is full does a record
            // get inserted into the Stats:sensor_stats table.
            Statement statement = createStatsStatement();
            // System.out.println("The frst query is select type_id, min(Min_TS)
            // as MinTS, max(Max_TS) as MaxTS, sum(Record_Count) as recCount
            // from sensor_stats group by type_id");
            ResultSet rs = statement
                    .executeQuery("select  type_id, min(Min_TS) as MinTS, max(Max_TS) as MaxTS, sum(Record_Count) as recCount from sensor_stats group by type_id");
            while (rs.next()) {
                eventStats = new nfse.gui.client.data.EventStats();
                eventStats.setTypeId(rs.getInt("Type_ID") + "");
                eventStats.setNewestEvent(rs.getTimestamp("MinTS") + "");
                eventStats.setOldestEvent(rs.getTimestamp("MaxTS") + "");
                eventStats.setEventCount(rs.getLong("recCount") + "");
                localMap.put(eventStats.getTypeId(), eventStats);
            }
            rs.close();
            statement.close();

            HashMap<String, SensorTypes> sensorMap = new HashMap<String, SensorTypes>();
            statement = createMetadataStatement();

            rs = statement
                    .executeQuery("select id, tool_id, type_name from sensors, type_classes where tool_id = type_id");

            while (rs.next()) {
                SensorTypes sensorType = new SensorTypes();
                sensorType.setSensorId(rs.getInt("id") + "");
                sensorType.setTypeId(rs.getInt("tool_id") + "");
                sensorType.setTypeName(rs.getString("type_name"));
                sensorMap.put(sensorType.getSensorId(), sensorType);
            }

            rs.close();
            statement.close();

            Iterator<String> sensorIt = sensorMap.keySet().iterator();

            while (sensorIt.hasNext()) {
                String sensorId = (String) sensorIt.next();
                statement = createMetadataStatement();
                String tableName = null;
                // System.out.println("The query is select table_name from
                // Temp_Tables where sensor_id = " + sensorId);
                rs = statement.executeQuery("select  table_name from Temp_Tables where (sensor_id = " + sensorId
                        + " and min_ts is null) ");
                if (rs.next()) {
                    tableName = rs.getString("table_name");
                }

                rs.close();
                statement.close();

                String database = ((SensorTypes) sensorMap.get(sensorId)).getTypeName();
                String typeId = ((SensorTypes) sensorMap.get(sensorId)).getTypeId();
                EventStats eStats = (EventStats) localMap.get(typeId);
                if (eStats == null) {
                    eStats = new nfse.gui.client.data.EventStats();
                    eStats.setTypeId(typeId);
                    eStats.setNewestEvent(null);
                    eStats.setOldestEvent(null);
                    eStats.setEventCount(0 + "");
                    localMap.put(eStats.getTypeId(), eStats);
                }

                // System.out.println("The database is " + database);

                if ((tableName == null) || (database == null) || (eStats == null)) {
                    continue;
                }
                statement = createDynamicStatement(database.toLowerCase());

                // System.out.println("the query is select min(startts) as
                // minTS, max(startts) as maxTS, count(*) as total from " +
                // tableName);

                try {
                    rs = statement
                            .executeQuery("select min(startts) as minTS, max(startts) as maxTS, count(*) as total from "
                                    + tableName);
                    if (rs.next()) {
                        java.sql.Timestamp minTS = rs.getTimestamp("minTS");
                        java.sql.Timestamp maxTS = rs.getTimestamp("maxTS");
                        int count = rs.getInt("total");

                        try {
                            java.sql.Timestamp compareMinTS = Timestamp.valueOf(eStats.getNewestEvent());
                            if (minTS != null && compareMinTS.compareTo(minTS) > 0)
                                eStats.setNewestEvent(minTS.toString());
                        } catch (Exception e) {
                            if (minTS != null)
                                eStats.setNewestEvent(minTS.toString());
                        }

                        try {
                            java.sql.Timestamp compareMaxTS = Timestamp.valueOf(eStats.getOldestEvent());
                            if (maxTS != null && compareMaxTS.compareTo(maxTS) < 0)
                                eStats.setOldestEvent(maxTS.toString());
                        } catch (Exception e) {
                            if (maxTS != null)
                                eStats.setOldestEvent(maxTS.toString());
                        }
                        count = count + new Integer(eStats.getEventCount()).intValue();
                        eStats.setEventCount(count + "");
                    }
                    rs.close();
                    statement.close();
                } catch (Exception e) {

                }

                String tempTS1 = eStats.getNewestEvent();
                String tempTS2 = eStats.getOldestEvent();
                eStats.setNewestEvent(tempTS2);
                eStats.setOldestEvent(tempTS1);
            }
        }

        catch (Exception e) {
            e.printStackTrace();
        }
        return localMap;
    }

    private Statement createDynamicStatement(String database) throws Exception {
        Statement s = null;
        try {
            Class.forName("org.postgresql.Driver");
            String url = "jdbc:postgresql://" + NetFSE.METADATA_HOST + "/" + database;
            Properties props = new Properties();
            props.setProperty("user", NetFSE.DYNAMIC_DB_USER);
            props.setProperty("password", NetFSE.DYNAMIC_DB_PASSWORD);
            props.setProperty("client_encoding", "UTF8");

            // System.out.println("The connect string is " + url);
            return DriverManager.getConnection(url, props).createStatement();
        } catch (Exception e) {
            System.out.println("Failed to get the database string with " + e.getMessage());

        }
        return s;

    }

    public CriticalServerEntries getCriticalServers(String timePeriod) {
        ArrayList<CriticalServer> criticalServers = new ArrayList<CriticalServer>();
        CriticalServerEntries cse = new CriticalServerEntries();
        cse.typeNames = NetFSE.getTypeNames();
        int[] types = NetFSE.getTypes();

        // First get the critical servers from the MetaData database
        try {

            Statement statement = createMetadataStatement();
            ResultSet rs = statement
                    .executeQuery("select Server_IP, Query_ID from Critical_Servers order by Server_IP asc");

            while (rs.next()) {
                String query_id = rs.getString("Query_ID");
                if (query_id.length() > 0) {
                    CriticalServer criticalServer = new CriticalServer();
                    criticalServer.setIp(rs.getString("Server_IP"));
                    criticalServer.setQueryId(query_id);
                    criticalServer.counts = new long[types.length];
                    criticalServers.add(criticalServer);
                }

            }
            rs.close();
            statement.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Second get the count for each sensor ordered by IP
        try {

            Iterator<CriticalServer> criticalServersIt = criticalServers.iterator();
            cse.entries = new CriticalServer[criticalServers.size()];
            Statement statement = createResultStatement();
            int idx = 0;
            while (criticalServersIt.hasNext()) {
                CriticalServer criticalServer = criticalServersIt.next();
                cse.entries[idx] = criticalServer;
                String queryId = criticalServer.getQueryId();
                // System.out.println("The query is select type_id, count(*) as
                // a from " + queryId + " group by type_id" );
                ResultSet rs = statement.executeQuery("select type_id, count(*) as a from " + queryId
                        + " group by type_id");

                while (rs.next()) {
                    int typeID = rs.getInt("type_id");
                    long count = rs.getLong("a");
                    for (int i = 0; i < types.length; i++) {
                        if (types[i] == typeID) {
                            cse.entries[idx].counts[i] += count;
                            break;
                        }
                    }
                }
                rs.close();
                idx++;
            }
            statement.close();
            return cse;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public SnapShotData getSnapShotStats(String timePeriod) {
        /**
         * Complicated HashMap
         * 
         * Key will be the agent
         * 
         * Each element at this level will be an arraylist holding each of Top
         * Sources, Top Targets(Dst), Top Destinations(Port Based)
         * 
         * 
         * The SnapShotDataTypeCategoryRecord is a little misleading but it is
         * designed to hold one of Top Sources, Top Target or Top Destinations
         */
        String sql = "";
        SnapShotData snapShotData = new SnapShotData();

        // String[] dataTypes = {"NetFlow"};
        // Integer array of all the types
        int[] allTypes = NetFSE.getTypes();

        ArrayList<Integer>[] sensorsByType = new ArrayList[allTypes.length];
        String[] sensorWheres = new String[allTypes.length];
        try {
            Statement statement = createMetadataStatement();
            for (int i = 0; i < allTypes.length; i++) {

                sensorsByType[i] = new ArrayList<Integer>();
                StringBuilder sensorWhere = new StringBuilder();

                sensorWhere.append(" ( ");
                int count = 0;
                ResultSet rs = statement.executeQuery("select id from sensors where tool_id = " + allTypes[i]);

                while (rs.next()) {
                    int sensorId = rs.getInt("id");
                    sensorsByType[i].add(sensorId);
                    count++;
                }

                // If no sensors continue to the next type
                if (sensorsByType[i].size() == 0)
                    continue;

                for (int q = 0; q < count; q++) {
                    if ((q > 0) && (q < count))
                        sensorWhere.append(" or ");
                    sensorWhere.append(" sensor_id = " + sensorsByType[i].get(q));
                }

                sensorWhere.append(" ) ");
                sensorWheres[i] = sensorWhere.toString();
                rs.close();

            }
            statement.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        GregorianCalendar today = new GregorianCalendar();
        today.setTime(new java.util.Date());
        snapShotData.setMaxTime(today.getTime().toString());

        today.add(Calendar.HOUR_OF_DAY, -6);
        // The next line is for testing only.
        // today.add(Calendar.YEAR, -4);
        snapShotData.setMinTime(today.getTime().toString());
        long milliTime = today.getTimeInMillis() / 1000;

        HashMap<String, HashMap<String, ArrayList<SnapShotDataTypeCategoryRecord>>> returnMap = new HashMap<String, HashMap<String, ArrayList<SnapShotDataTypeCategoryRecord>>>();

        for (int i = 0; i < allTypes.length; i++) {
            HashMap<String, ArrayList<SnapShotDataTypeCategoryRecord>> localMap = new HashMap<String, ArrayList<SnapShotDataTypeCategoryRecord>>();

            // Get the Top Source hits
            try {
                ArrayList<SnapShotDataTypeCategoryRecord> topSourcesList = new ArrayList<SnapShotDataTypeCategoryRecord>();
                Statement statement = createStatsStatement();
                String query = "select ip, sum(num_hits) as totalHits from src_ip_stats " + " where (time_interval >= "
                        + milliTime + " ) and " + sensorWheres[i] + " group by ip order by totalHits desc limit 10";

                //System.out.println("The src_ip_stats query is " + query);
                ResultSet rs = statement.executeQuery(query);

                while (rs.next()) {
                    SnapShotDataTypeCategoryRecord ssData = new SnapShotDataTypeCategoryRecord();
                    ssData.setAddress(rs.getString("ip"));
                    ssData.setAddressURL(NetFSE.IP_LINK_FACTORY.generateLink(rs.getString("ip")));
                    ssData.setHits(rs.getInt("totalHits") + "");
                    topSourcesList.add(ssData);
                }
                rs.close();
                statement.close();

                localMap.put("Top Sources", topSourcesList);

            } catch (Exception e) {
                e.printStackTrace();
            }
            // Get the Top Destination hits
            try {
                ArrayList<SnapShotDataTypeCategoryRecord> topTargetsList = new ArrayList<SnapShotDataTypeCategoryRecord>();
                Statement statement = createStatsStatement();
                sql = "select ip, sum(num_hits) as totalHits from dst_ip_stats " + " where (time_interval >= "
                        + milliTime + " ) and " + sensorWheres[i] + " group by ip order by totalHits desc limit 10";
                
                //System.out.println("The dst_ip_stats query is " + sql);

                ResultSet rs = statement.executeQuery(sql);

                while (rs.next()) {
                    SnapShotDataTypeCategoryRecord ssData = new SnapShotDataTypeCategoryRecord();
                    ssData.setAddress(rs.getString("ip"));
                    ssData.setAddressURL(NetFSE.IP_LINK_FACTORY.generateLink(rs.getString("ip")));
                    ssData.setHits(rs.getInt("totalHits") + "");
                    topTargetsList.add(ssData);
                }
                rs.close();
                statement.close();
                localMap.put("Top Targets", topTargetsList);

            } catch (Exception e) {
                e.printStackTrace();
            }
            // Get the Top Port hits
            try {
                ArrayList<SnapShotDataTypeCategoryRecord> topPortsList = new ArrayList<SnapShotDataTypeCategoryRecord>();

                Statement statement = createStatsStatement();

                sql = "select port, sum(num_hits) as totalHits from dst_port_stats " + " where (time_interval >= "
                        + milliTime + " ) and " + sensorWheres[i] + " group by port order by totalHits desc limit 10";
                
                //System.out.println("The dst_port_stats query is " + sql);

                ResultSet rs = statement.executeQuery(sql);

                while (rs.next()) {
                    SnapShotDataTypeCategoryRecord ssData = new SnapShotDataTypeCategoryRecord();
                    ssData.setPort(rs.getInt("port") + "");
                    ssData.setHits(rs.getInt("totalHits") + "");
                    topPortsList.add(ssData);
                }
                rs.close();
                statement.close();
                localMap.put("Top Ports", topPortsList);

            } catch (Exception e) {
                e.printStackTrace();
            }

            returnMap.put(allTypes[i] + "", localMap);
        }

        snapShotData.setSnapShotMap(returnMap);
        return snapShotData;

    }

    public ArrayList<DiskSpace> getDiskUsage() {
        ArrayList<DiskSpace> aList = new ArrayList<DiskSpace>();
        try {
            String line;

            Process p = Runtime.getRuntime().exec("df");

            BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
            int lineCount = 0;
            while ((line = br.readLine()) != null) {

                String[] result = line.split("\\s+");
                // LineCount = 0 is the header. Skip header
                if ((result.length > 4) && lineCount != 0) {
                    DiskSpace diskSpace = new DiskSpace();
                    diskSpace.setTotalDiskSpace(result[1]);
                    diskSpace.setSpaceUsed(result[2]);
                    diskSpace.setSpaceAvailable(result[3]);
                    diskSpace.setPercentUsed(result[4]);
                    diskSpace.setDataDirectory(result[5]);
                    aList.add(diskSpace);
                }
                lineCount++;

            }
            br.close();
            p.destroy();

            // System.out.println("The df is " + output.toString());
        } catch (Exception ex) {
            System.out.println("The error is " + ex.getMessage());
            ex.printStackTrace();
        }

        return aList;
    }

    public HashMap<String, SensorTypes> getSensorTypes() {
        HashMap<String, SensorTypes> dataMap = new HashMap<String, SensorTypes>();
        try {
            Statement statement = createMetadataStatement();

            // Figure what the types are
            // Then have a second loop that iterates on the entries in the
            // hashmap from the first loop.

            ResultSet rs = statement.executeQuery("select type_id, type_name from  type_classes");
            while (rs.next()) {
                SensorTypes sTypes = new SensorTypes();
                sTypes.setTypeId(rs.getInt("type_id") + ""); // Sensor ID
                sTypes.setTypeName(rs.getString("type_name"));
                dataMap.put(sTypes.getTypeId(), sTypes);
            }
            rs.close();
            statement.close();
        } catch (Exception ex) {
            System.out.println("The error is " + ex.getMessage());
            ex.printStackTrace();
        }

        return dataMap;
    }

}
